#include <iostream>
#include <cstdio>
#include <conio.h>
#include <windows.h>
#include <fstream>
#include <sstream>

using namespace std;


class Timer{//Small timer class to time in-game events
      private:
              clock_t start_time;
      public:
             void start(){
                          start_time=clock();
                          };
             float elapTime(){
                     return ((float)(clock()-start_time))/CLOCKS_PER_SEC;
                     };
      };
      
class Player{
      private:
              struct food{
                     int pos_x,pos_y;
                     int bounce,weight,cook;
                     };
              struct power{
                     int pos_x,pos_y;
                     int type;//Different power-ups
                     int power_spawn;//Power is in play
                     };
              food food_list[5];
              power power_up;
              int pos_player,pos_pan,pos_drop;
              char map[16][16];
              int points,lives,amount;
              int powerup_state;//Handle power ups
              Timer powerup_time;
      public:
             Player(){
                      points=0;
                      lives=5;
                      amount=0;
                      //Fill map with empty character
                      for(int i=0;i<16;i++){
                         for(int j=0;j<16;j++){
                            map[i][j]=' ';
                         }
                      }
                      //Place player in the middle of the map
                      pos_player=3;//Player can be in one of 5 positions
                      map[12][7]='p';
                      map[12][8]='p';
                      map[13][7]='p';
                      map[13][8]='p';
                      map[14][7]='p';
                      map[14][8]='p';
                      map[15][7]='p';
                      map[15][8]='p';
                      //Place pan with the player
                      pos_pan=0;//Pan can be in the left or right of the player
                      map[13][6]='x';
                      //Player has no power-up
                      powerup_state=0;
                      power_up.power_spawn=0;
                      };
             int getLives(){
                 return lives;
             }
             void printMap(){
                  updateFood();
                  updatePower();
                  for(int i=0;i<16;i++){
                         for(int j=0;j<16;j++){
                            cout<<map[i][j];
                         }
                         cout<<endl;
                      }
                  cout<<endl;
                  cout<<"Score: "<<points<<endl;
                  };
             void movePan(int pos){
                  if(powerup_state!=1){
                       switch(pos){
                              case 1:
                                   if(pos_pan==0){
                                                  map[13][0]='x';
                                                  map[13][3]=' ';
                                                 }
                                   else if(pos_pan==1){
                                        map[13][3]='x';
                                        map[13][0]=' ';
                                        }
                              break;
                              case 2:
                                   if(pos_pan==0){
                                                  map[13][3]='x';
                                                  map[13][6]=' ';
                                                 }
                                   else if(pos_pan==1){
                                        map[13][6]='x';
                                        map[13][3]=' ';
                                        }
                              break;
                              case 3:
                                   if(pos_pan==0){
                                                  map[13][6]='x';
                                                  map[13][9]=' ';
                                                 }
                                   else if(pos_pan==1){
                                        map[13][9]='x';
                                        map[13][6]=' ';
                                        }
                              break;
                              case 4:
                                   if(pos_pan==0){
                                                  map[13][9]='x';
                                                  map[13][12]=' ';
                                                 }
                                   else if(pos_pan==1){
                                        map[13][12]='x';
                                        map[13][9]=' ';
                                        }
                              break;
                              case 5:
                                   if(pos_pan==0){
                                                  map[13][12]='x';
                                                  map[13][15]=' ';
                                                 }
                                   else if(pos_pan==1){
                                        map[13][15]='x';
                                        map[13][12]=' ';
                                        }
                              break;
                              }
                       }
                       else{
                            switch(pos){
                              case 1:
                                   map[13][0]='x';
                                   map[13][3]='x';
                              break;
                              case 2:
                                   map[13][3]='x';
                                   map[13][6]='x';
                              break;
                              case 3:
                                   map[13][6]='x';
                                   map[13][9]='x';
                              break;
                              case 4:
                                   map[13][9]='x';
                                   map[13][12]='x';
                              break;
                              case 5:
                                   map[13][12]='x';
                                   map[13][15]='x';
                              break;
                              }
                            }
                  };
             void movePlayer(int pos){
                  //Clear old player positions
                  for(int i=12;i<16;i++){
                         for(int j=0;j<16;j++){
                            if(map[i][j]=='p'||map[i][j]=='x'){
                                                               map[i][j]=' ';
                                                               }
                         }
                      }
                  switch(pos){
                              case 1:
                                   pos_player=1;
                                   map[12][1]='p';
                                   map[12][2]='p';
                                   map[13][1]='p';
                                   map[13][2]='p';
                                   map[14][1]='p';
                                   map[14][2]='p';
                                   map[15][1]='p';
                                   map[15][2]='p';
                              break;
                              case 2:
                                   pos_player=2;
                                   map[12][4]='p';
                                   map[12][5]='p';
                                   map[13][4]='p';
                                   map[13][5]='p';
                                   map[14][4]='p';
                                   map[14][5]='p';
                                   map[15][4]='p';
                                   map[15][5]='p';
                              break;
                              case 3:
                                   pos_player=3;
                                   map[12][7]='p';
                                   map[12][8]='p';
                                   map[13][7]='p';
                                   map[13][8]='p';
                                   map[14][7]='p';
                                   map[14][8]='p';
                                   map[15][7]='p';
                                   map[15][8]='p';
                              break;
                              case 4:
                                   pos_player=4;
                                   map[12][10]='p';
                                   map[12][11]='p';
                                   map[13][10]='p';
                                   map[13][11]='p';
                                   map[14][10]='p';
                                   map[14][11]='p';
                                   map[15][10]='p';
                                   map[15][11]='p';
                              break;
                              case 5:
                                   pos_player=5;
                                   map[12][13]='p';
                                   map[12][14]='p';
                                   map[13][13]='p';
                                   map[13][14]='p';
                                   map[14][13]='p';
                                   map[14][14]='p';
                                   map[15][13]='p';
                                   map[15][14]='p';
                              break;
                              }
                  movePan(pos);
                  };
             void rotatePan(int pos){
                  if(pos==0){
                             pos_pan=1;
                             }
                  else if(pos==1){
                       pos_pan=0;
                       }
                  movePan(pos_player);
                  };
             int getPlayerPos(){
                 return pos_player;
                 };
             int getPanPos(){
                 return pos_pan;
                 };
             int getScore(){
                 return points;
                 };
             void dropFood(){
                  if(amount<5&&rand()%25==0){
                                pos_drop=(rand()%6)*3;
                                map[0][pos_drop]='o';
                                food_list[amount].pos_x=0;
                                food_list[amount].pos_y=pos_drop;
                                food_list[amount].bounce=0;//Going down
                                food_list[amount].weight=(rand()%2)+1;
                                food_list[amount].cook=(rand()%2)*2+3;//Hits until food is cooked
                                amount++;
                                }
                  };
             void delFood(int pos){
                  for(int j=pos;j<amount;j++){
                          food_list[j].pos_x=food_list[j+1].pos_x;
                          food_list[j].pos_y=food_list[j+1].pos_y;
                          food_list[j].bounce=food_list[j+1].bounce;
                          food_list[j].weight=food_list[j+1].weight;
                          food_list[j].cook=food_list[j+1].cook;
                  }
                  amount--;
                  };
             void updateFood(){
                  for(int i=0;i<amount;i++){
                          if(food_list[i].bounce==0){//Going down
                             if(food_list[i].pos_x<15){
                                //Update the map display
                                if(map[food_list[i].pos_x+food_list[i].weight][food_list[i].pos_y]==' '){
                                   map[food_list[i].pos_x+food_list[i].weight][food_list[i].pos_y]='o';
                                }
                                //Clear last position
                                if(map[food_list[i].pos_x][food_list[i].pos_y]=='o'){
                                   map[food_list[i].pos_x][food_list[i].pos_y]=' ';
                                }
                                //Update food coordinates
                                food_list[i].pos_x+=food_list[i].weight;
                                }
                             else{//Food drops on the ground
                                   //Clear map bottom
                                   map[15][food_list[i].pos_y]=' ';      
                                   //Clear food list
                                   delFood(i);
                                   //Lose a life
                                   lives--;
                                   break;
                                }
                             }
                          else if(food_list[i].bounce==1){//Going up
                             if(food_list[i].pos_x>0){
                                //Update the map display
                                map[food_list[i].pos_x-food_list[i].weight][food_list[i].pos_y]='o';
                                map[food_list[i].pos_x][food_list[i].pos_y]=' ';
                                //Update food coordinates
                                food_list[i].pos_x-=food_list[i].weight;
                                }
                             else{//Food reaches the top
                                  food_list[i].bounce=0;
                                  }
                             }
                          if(map[food_list[i].pos_x+1][food_list[i].pos_y]=='x'){//Food hits pan
                               if(food_list[i].cook>0){//Food is not cooked
                                  food_list[i].bounce=1;
                                  food_list[i].cook--;
                                  if(powerup_state!=2){
                                                       points++;
                                                       }
                                  else{
                                       points+=2;
                                       }
                                  }
                               else{//Food is cooked
                                    map[food_list[i].pos_x][food_list[i].pos_y]=' '; 
                                    delFood(i);
                                    if(powerup_state!=2){
                                                       points+=10;
                                                       }
                                    else{
                                       points+=20;
                                       }
                                    }   
                               }
                      }
                  };
             void dropPower(){
                  if(rand()%50==0&&power_up.power_spawn==0){
                     pos_drop=(rand()%6)*3;
                     map[0][pos_drop]='*';
                     power_up.pos_x=0;
                     power_up.pos_y=pos_drop;
                     power_up.type=(rand()%2)+1;//1 = double pan; 2 = score multiplier
                     power_up.power_spawn=1;
                     powerup_time.start();
                     }
                  };
             void updatePower(){
                  if(powerup_time.elapTime()>=10){
                                                powerup_state=0;
                                                }
                  if(power_up.power_spawn==1){
                     if(map[power_up.pos_x+1][power_up.pos_y]==' '){//Power-up is falling
                                map[power_up.pos_x+1][power_up.pos_y]='*';
                                map[power_up.pos_x][power_up.pos_y]=' ';
                                power_up.pos_x++;
                                }
                     else if(map[power_up.pos_x+1][power_up.pos_y]=='x'){//Power-up hit the pan
                       map[power_up.pos_x][power_up.pos_y]=' ';
                       powerup_state=power_up.type;
                       power_up.power_spawn=0;
                       }
                     else if(power_up.pos_x==15){//Power-up hits the floor
                       map[15][power_up.pos_y]=' ';
                       power_up.power_spawn=0;
                       }
                     }
                  movePan(pos_player);
                  };
             bool dead(){
                  if(lives==0){
                               return true;
                               }
                  else{
                       return false;
                       }
                  };
      };

int main(void){
    srand(time(NULL));
    bool game_over=false;
    bool play_again=true;
    char input,change,drop;
    int high_score,game_type;
    Player chef;
    Timer game_time;
    //Load high score from file (will be data base in the real game)
    ifstream fin("hs.txt");//Create input stream
    if (fin.is_open()){
       fin>>high_score;
    }
    fin.close();//Close input stream
    //Main menu befor ethe game
    cout<<endl<<"Welcome to FOOD FRENZY!"<<endl<<endl;
    cout<<"Choose a game mode:"<<endl;
    cout<<"[1] Classic Mode (3 minutes)"<<endl;
    cout<<"[2] Arcade Mode (3 lives)"<<endl;
    cin>>game_type;
    switch(game_type){
                      case 1:
                           cout<<endl<<"You chose Classic Mode! Game will start soon."<<endl;
                      break;
                      case 2:
                           cout<<endl<<"You chose Arcade Mode! Game will start soon."<<endl;
                      break;
                      default:
                              cout<<endl<<"Wrong selection! Try again."<<endl;
                              getch();
                              return 0;
                      break;
                      }
    Sleep(2000);
    chef.printMap();
    if(game_type==1){
                     game_time.start();
                     cout<<"Time: "<<(int)((180.0 - game_time.elapTime())/60.0)<<":"<<(180.0 - game_time.elapTime())-((int)((180.0 - game_time.elapTime())/60.0)*60)<<endl;
                     }
    else if(game_type==2){
         cout<<"Lives: "<<chef.getLives()<<endl;
         }
    cout<<"High Score: "<<high_score<<endl;
    while(!game_over){
                      if(_kbhit()){//Key is pressed
                      input=_getch();
                      switch(input){
                                    case 'w'://Move up
                                         //DOES NOTHING IN THE GAME!
                                    break;
                                    case 'a'://Move left
                                         change=chef.getPlayerPos()-1;
                                         if(change>0&&change<6){
                                                                chef.movePlayer(change);
                                                                }
                                    break;
                                    case 's'://Move down
                                         //DOES NOTHING IN THE GAME!
                                    break;
                                    case 'd'://Move right
                                         change=chef.getPlayerPos()+1;
                                         if(change>0&&change<6){
                                                                chef.movePlayer(change);
                                                                }
                                    break;
                                    case 'l'://Rotate
                                         chef.rotatePan(chef.getPanPos());
                                    break;
                                    case 'e'://Exit
                                         game_over=true;
                                    break;
                                    }
                      }else{
                            Sleep(200);//Sleep time can change for added difficuty
                            }
                      //Drop food at random
                      chef.dropFood();
                      //Drop power-up at random
                      chef.dropPower();
                      //Check if dead
                      if(game_type==1){
                                       if(game_time.elapTime()>=180){//3 minutes
                                                                    game_over=true;
                                                                    }
                                       system("cls");
                                       chef.printMap();
                                       cout<<"Time: "<<(int)((180.0 - game_time.elapTime())/60.0)<<":"<<(180.0 - game_time.elapTime())-((int)((180.0 - game_time.elapTime())/60.0)*60)<<endl;
                                       cout<<"High Score: "<<high_score<<endl;
                                       }
                      else if(game_type==2){
                                       game_over=chef.dead();
                                       system("cls");
                                       chef.printMap();
                                       cout<<"Lives: "<<chef.getLives()<<endl;
                                       cout<<"High Score: "<<high_score<<endl;
                      }
                      }
    cout<<"\nGAME OVER!\n";
    //Save new high score
    if(chef.getScore()>high_score){
       cout<<"NEW HIGH SCORE!!!"<<endl;
       ofstream fout;//Create an output stream
       fout.open("hs.txt");//Create output file
       fout<<chef.getScore();
       fout.close();//Close output stream
    }
    Sleep(2000);
    getch();
    return 0;
}
